#include <avr/io.h>
#include <avr/interrupt.h>
#include "serial.h"

static Serialp _gbl_serial;

ISR(USART_RX_vect) {
  uint8_t data = UDR0;

  uint8_t next_id = (_gbl_serial->in_tail+1) % SERIAL_IN_BUFFER;
  if(next_id != _gbl_serial->in_head) {
    _gbl_serial->in[_gbl_serial->in_tail] = data;
    //_gbl_serial->in_tail++;
    //_gbl_serial->in_tail %= SERIAL_IN_BUFFER;
    _gbl_serial->in_tail = next_id;
  } else {
    //PORTD |= _BV(PD7); // Turn on Error LED if bad
  }

  /*
  if(data & 1) {
    PORTB |= _BV(PB2);
  } else {
    PORTB &= ~_BV(PB2);
  }
  */
}

void serial_init(Serialp serial) {
  _gbl_serial = serial;  // for the interrupt
  serial->in_head = 0;
  serial->in_tail = 0;

  UBRR0L = 21; // 20.0MHz, 115.2k baud
  UCSR0A |= _BV(U2X0);
  //UBRRL = 10; // 10MHz, 57600 baud
  
  // Enable transmitter and receiver, and receive interrupt
  UCSR0B = _BV(TXEN0) | _BV(RXEN0) | _BV(RXCIE0);

  // 8 data, 1 stop
  UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); // Specifies 8-bits
}

int8_t serial_read(Serialp serial, uint8_t *ch) {
  if(serial->in_head == serial->in_tail) {
    return 0;
  }

  *ch = serial->in[serial->in_head];
  serial->in_head++;
  serial->in_head %= SERIAL_IN_BUFFER;
  return 1;
}

void serial_write(Serialp serial, uint8_t ch) {
  while(!(UCSR0A & (1<<UDRE0)));
  UDR0 = ch;
}
